package se.rende.myrss;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLConnection;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Locale;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.xml.sax.InputSource;

import se.rende.myrss.data.Channel;
import se.rende.myrss.data.DataService;
import se.rende.myrss.data.Filter;

import com.sun.syndication.feed.synd.SyndEntry;
import com.sun.syndication.feed.synd.SyndFeed;
import com.sun.syndication.io.FeedException;
import com.sun.syndication.io.SyndFeedInput;

/**
 * Download a list of rss channels to speed up app download.
 * For each Channel entity in the datastore, download items into Item entities. 
 * Only store items that are later than those in the datastore.
 */
@SuppressWarnings("serial")
public class CacheRssServlet extends HttpServlet {
	private static final SimpleDateFormat headerDateFormat = new SimpleDateFormat("EEE MMM dd HH:mm:ss z yyyy", Locale.US);
	private DataService dataService;
	
	@Override
	public void init(ServletConfig config) throws ServletException {
		dataService = (DataService) config.getServletContext().getAttribute("data");
	}

	public void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws IOException {
		resp.setContentType("text/plain");
		resp.setCharacterEncoding("utf-8");
				
		List<Channel> channels = dataService.getChannels();
		for (Channel channel : channels) {
			try {
				Date latestItem = dataService.getLatestItemDate(channel);
				URL feedUrl = new URL(channel.getUrl());
				URLConnection urlConnection = feedUrl.openConnection();
				urlConnection.setConnectTimeout(10000);
				urlConnection.setReadTimeout(10000);
				urlConnection.setDoOutput(true);
				urlConnection.setRequestProperty("If-Modified-Since", headerDateFormat.format(latestItem));
				
				if (urlConnection instanceof HttpURLConnection) {
					HttpURLConnection httpConnection = (HttpURLConnection) urlConnection;
					int code = httpConnection.getResponseCode();
					if (code == 200) {
						BufferedInputStream is = new BufferedInputStream(httpConnection.getInputStream());
						skipSpace(is);
						SyndFeedInput input = new SyndFeedInput();
						SyndFeed feed = input.build(new InputSource(is));
						is.close();
												
						for (Object entry : feed.getEntries()) {
							SyndEntry syndEntry = (SyndEntry) entry;
							syndEntry.setSource(feed);
							if (syndEntry.getPublishedDate().after(latestItem)) {
								dataService.addChannelItem(
										channel,
										syndEntry.getTitle(),
										syndEntry.getLink(),
										syndEntry.getPublishedDate(),
										syndEntry.getAuthor(),
										syndEntry.getDescription().getValue());
							}
						}
					}
				}
			} catch (FeedException e) {
				throw new IOException("can't read rss into feed data structure", e);
			}
		}
	}

	/**
	 * Skip chars for is until a '<'
	 * @param is
	 * @throws IOException
	 */
	private static void skipSpace(InputStream is) throws IOException {
		while (true) {
			is.mark(1);
			int ch = is.read();
			if (ch <= 0 || ch == '<') {
				is.reset();
				break;
			}
			
		}
	}

	private void filterEntry(String url, SyndEntry syndEntry) {
		String s = syndEntry.getDescription().getValue();
		List<Filter> filters = dataService.getFiltersByUrl(url);
		for (Filter filter : filters) {
			s = filter.execute(s, syndEntry);
		}		
		syndEntry.getDescription().setValue(s);
	}

}
